package org.wangtian.youxueban.excel.work;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 *
 */
public class Mpmanage {
    public static void main(String[] args) {
        List<YuanLiaoBo> yuanLiaoBos = initYuanLiaoBo();
        List<ChanPinBo> chanPinBos = initChanPinBo();
        getChanPinListPerYuanLiao(chanPinBos, yuanLiaoBos);
    }

    /**
     * 初始化原料
     *
     * @return
     */
    public static List<YuanLiaoBo> initYuanLiaoBo() {
        List<YuanLiaoBo> yuanLiaoBos = new ArrayList<>();
        yuanLiaoBos.add(new YuanLiaoBo(6000, 100, 10, 1, 001));
        yuanLiaoBos.add(new YuanLiaoBo(6000, 100, 20, 1000, 002));
        yuanLiaoBos.add(new YuanLiaoBo(8000, 100, 10, 3, 003));
        return yuanLiaoBos;
    }

    /**
     * 初始化产品
     *
     * @return
     */
    public static List<ChanPinBo> initChanPinBo() {
        List<ChanPinBo> chanPinBos = new ArrayList<>();
        chanPinBos.add(new ChanPinBo(1200, 100, 10, 6));
        chanPinBos.add(new ChanPinBo(1600, 100, 10, 8));
        chanPinBos.add(new ChanPinBo(1800, 100, 10, 6));
        chanPinBos.add(new ChanPinBo(2200, 100, 20, 7));
        chanPinBos.add(new ChanPinBo(708, 100, 20, 30));
        chanPinBos.add(new ChanPinBo(2400, 100, 10, 3));
        chanPinBos.add(new ChanPinBo(2520, 100, 10, 2));
        return chanPinBos;
    }

    /**
     * 获取一个原料上单个产品的可能的个数组成集合
     *
     * @param chanPinBos
     * @param yuanLiaoBos
     */
    public static void getChanPinListPerYuanLiao(List<ChanPinBo> chanPinBos, List<YuanLiaoBo> yuanLiaoBos) {
        List<BestBo> bestBos = new ArrayList<>();
        List<InitBo> initBos = new ArrayList<>();
        for (YuanLiaoBo yuanLiaoBo : yuanLiaoBos) {
            int yuanLiaoBoHeight = yuanLiaoBo.getHeight();
            int yuanLiaoBoLength = yuanLiaoBo.getLength();
            int yuanLiaoBoWidth = yuanLiaoBo.getWidth();
            int yuanLiaoBoRemainNum = yuanLiaoBo.getRemainNum();
            if (yuanLiaoBoRemainNum <= 0) {
                continue;
            }
            List<ChanPinBo> newChanPinList = new ArrayList<>();
            List maxLength = new ArrayList();
            List<List<ChanPinBo>> qiongquAllList = new ArrayList<>();
            for (ChanPinBo chanPinBo : chanPinBos) {
                if (chanPinBo.getNeedTotalNum() <= 0) {
                    continue;
                }
                if (chanPinBo.getHeight() == yuanLiaoBoHeight && chanPinBo.getWidth() == yuanLiaoBoWidth) {
                    newChanPinList.add(chanPinBo);
                    List<ChanPinBo> qiongquList = new ArrayList();
                    for (int i = chanPinBo.getCurrentNum(); i < chanPinBo.getNeedTotalNum(); i++) {
                        if ((chanPinBo.getLength() * i) <= yuanLiaoBoLength) {
                            int danGeChanPin = chanPinBo.getLength() * i;
                            ChanPinBo chanPinBo1 = new ChanPinBo(chanPinBo.getLength(), chanPinBo.getWidth(), chanPinBo.getHeight(), chanPinBo.getNeedTotalNum());
                            chanPinBo1.setSumLength(danGeChanPin);
                            chanPinBo1.setCurrentNum(i);
                            qiongquList.add(chanPinBo1);
                        } else {
                            break;
                        }
                    }
                    maxLength.add(qiongquList.size());
                    qiongquAllList.add(qiongquList);
                }
            }
            Integer[] maxLengthArray = new Integer[maxLength.size()];
            maxLength.toArray(maxLengthArray);
            initBos.add(new InitBo(qiongquAllList, yuanLiaoBo, maxLengthArray, newChanPinList));
            BestBo bestBo = getMinYuLiaoPerYuanLiaoChanPinList(qiongquAllList, yuanLiaoBo, maxLengthArray, newChanPinList);
            bestBos.add(bestBo);
        }
        Collections.sort(bestBos);//对余料最小的进行优先使用的排序
        //System.out.println(bestBos);
        for (BestBo bestBo : bestBos) {
            YuanLiaoBo yuanLiaoBo = bestBo.getYuanLiaoBo();
            InitBo initBo = null;
            for (InitBo initBo1 : initBos) {
                if (yuanLiaoBo.getCode() == initBo1.getYuanLiaoBo().getCode()) {
                    initBo = initBo1;
                    break;
                }
            }
            if (initBo != null) {
                List<ResultBo> resultBos = getAllMinYuLiaoPerYuanLiaoChanPinList(initBo.getQiongquAllList(), initBo.getYuanLiaoBo(), initBo.getMaxLen(), initBo.getChanPinBos());
                System.out.println(resultBos);
            }
        }
    }

    /**
     * 获取一个原料上最后的产品及个数的组合，余料最小
     *
     * @param qiongquAllList
     * @param yuanLiaoBo
     * @param maxLen
     */
    public static List<ResultBo> getAllMinYuLiaoPerYuanLiaoChanPinList(List<List<ChanPinBo>> qiongquAllList, YuanLiaoBo yuanLiaoBo, Integer[] maxLen, List<ChanPinBo> chanPinBos) {
        List<int[]> allZuHe = getAllZuHeList(maxLen);
        int allNeeds = 0;
        List<ResultBo> resultBos = new ArrayList<>();
        while (true) {
            int yuanLiaoBoLength = yuanLiaoBo.getLength();
            if (yuanLiaoBo.getRemainNum() > 0) {
                int min = yuanLiaoBoLength;
                int tempSum = 0;
                int[] resultUnit = null;
                for (int[] unit : allZuHe) {
                    tempSum = 0;
                    allNeeds = 0;
                    for (int i = 0; i < qiongquAllList.size(); i++) {
                        int unitIndex = unit[i];
                        int planNum = qiongquAllList.get(i).get(unitIndex).getCurrentNum();
                        int needNum = chanPinBos.get(i).getNeedTotalNum();
                        allNeeds = allNeeds + needNum;
                        if (planNum <= needNum) {
                            int unitLength = qiongquAllList.get(i).get(unitIndex).getSumLength();
                            tempSum += unitLength;
                        } else {
                            continue;
                        }
                    }
                    if (allNeeds == 0) {
                        break;
                    }
                    int tempRemainLength = yuanLiaoBoLength - tempSum;
                    if (tempRemainLength >= 0 && min > tempRemainLength) {

                        min = tempRemainLength;
                        resultUnit = unit;
                        if (min == 0) {
                            break;
                        }
                    }
                }
                if (resultUnit != null) {
                    ResultBo resultBo = new ResultBo();
                    YuanLiaoBo yuanLiaoBoClone = new YuanLiaoBo(yuanLiaoBo);
                    resultBo.setYuanLiaoBo(yuanLiaoBoClone);
                    List<ChanPinBo> chanPinBos1 = new ArrayList<>();
                    resultBo.setChanPinBos(chanPinBos1);
                    resultBo.setMin(min);
                    resultBos.add(resultBo);
                    for (int i = 0; i < qiongquAllList.size(); i++) {
                        int unitIndex = resultUnit[i];
                        int num = qiongquAllList.get(i).get(unitIndex).getCurrentNum();

                        int length = qiongquAllList.get(i).get(unitIndex).getLength();
                        if (num != 0) {
                            chanPinBos.get(i).setNeedTotalNum(chanPinBos.get(i).getNeedTotalNum() - num);
                            chanPinBos.get(i).setCurrentNum(num);
                            ChanPinBo chanPinBo = new ChanPinBo(chanPinBos.get(i));
                            chanPinBos1.add(chanPinBo);
                        }
                    }
                    yuanLiaoBo.setRemainNum(yuanLiaoBo.getRemainNum() - 1);
                } else {
                    if (allNeeds == 0) {
                        break;
                    }
                }
            } else {
                break;
            }
            if (allNeeds == 0) {
                break;
            }
        }
        return resultBos;
    }


    /**
     * 获取一个原料上最后的产品及个数的组合，余料最小
     *
     * @param qiongquAllList
     * @param yuanLiaoBo
     * @param maxLen
     */
    public static BestBo getMinYuLiaoPerYuanLiaoChanPinList(List<List<ChanPinBo>> qiongquAllList, YuanLiaoBo yuanLiaoBo, Integer[] maxLen, List<ChanPinBo> chanPinBos) {
        BestBo bestBo = new BestBo();
        List<int[]> allZuHe = getAllZuHeList(maxLen);
        int yuanLiaoBoLength = yuanLiaoBo.getLength();
        if (yuanLiaoBo.getRemainNum() > 0) {
            int min = yuanLiaoBoLength;
            int tempSum = 0;
            int[] resultUnit = null;
            for (int[] unit : allZuHe) {
                tempSum = 0;
                for (int i = 0; i < qiongquAllList.size(); i++) {
                    int unitIndex = unit[i];
                    int unitLength = qiongquAllList.get(i).get(unitIndex).getSumLength();
                    tempSum += unitLength;
                }
                int tempRemainLength = yuanLiaoBoLength - tempSum;
                if (tempRemainLength >= 0 && min > tempRemainLength) {
                    min = tempRemainLength;
                    resultUnit = unit;
                    if (min == 0) {
                        break;
                    }
                }
            }
            List<ChanPinBo> chanPinBos1 = new ArrayList<>();
            for (int i = 0; i < qiongquAllList.size(); i++) {
                int unitIndex = resultUnit[i];
                int num = qiongquAllList.get(i).get(unitIndex).getCurrentNum();
                int length = qiongquAllList.get(i).get(unitIndex).getLength();
                if (num != 0) {
                    chanPinBos1.add(qiongquAllList.get(i).get(unitIndex));
                }
            }
            bestBo.setMin(min);
            bestBo.setYuanLiaoBo(yuanLiaoBo);
            bestBo.setChanPinBos(chanPinBos1);
        }
        return bestBo;
    }


    /**
     * 获取集合矩阵所对应所有的组合情况
     * <p>
     * [0,0,0,0,0]
     * [1,1,1,1,1]
     * [2,2,2,2,2]
     * [3,3,3,3,3]
     * [4,4,4,4,4]
     *
     * @param maxLen
     * @return
     */
    public static List<int[]> getAllZuHeList(Integer[] maxLen) {
        int[] add = new int[maxLen.length];
        int sum = 1;
        List<int[]> allZuHe = new ArrayList();
        for (int i = 0; i < maxLen.length; i++) {
            sum = sum * maxLen[i];
        }
        int ccindex = 0;

        for (int j = 0; j < sum; j++) {
            int[] ddd = add.clone();
            allZuHe.add(ddd);
            if (add[ccindex] < maxLen[ccindex] - 1) {
                add[ccindex]++;
            } else {
                if (add.length > ccindex + 1) {
                    while (add[ccindex + 1] <= maxLen[ccindex + 1]) {
                        boolean isOk = add(add, ccindex, maxLen);
                        if (isOk) {
                            break;
                        }
                    }
                }
            }
        }
        return allZuHe;
    }

    /**
     * 递归所有的组合情况，将数据进行加运算，进制采用灵活进制
     * [0, 0, 0, 0, 0]
     * [1, 0, 0, 0, 0]
     * [2, 0, 0, 0, 0]
     * [3, 0, 0, 0, 0]
     * [4, 0, 0, 0, 0]
     * [5, 0, 0, 0, 0]
     * [0, 1, 0, 0, 0]
     * [1, 1, 0, 0, 0]
     * [2, 1, 0, 0, 0]
     * [3, 1, 0, 0, 0]
     * [4, 1, 0, 0, 0]
     * [5, 1, 0, 0, 0]
     * [0, 2, 0, 0, 0]
     * [1, 2, 0, 0, 0]
     * [2, 2, 0, 0, 0]
     * [3, 2, 0, 0, 0]
     * [4, 2, 0, 0, 0]
     * [5, 2, 0, 0, 0]
     * [0, 3, 0, 0, 0]
     * [1, 3, 0, 0, 0]
     * [2, 3, 0, 0, 0]
     * [3, 3, 0, 0, 0]
     * [4, 3, 0, 0, 0]
     * [5, 3, 0, 0, 0]
     * [0, 0, 1, 0, 0]
     * [1, 0, 1, 0, 0]
     * [2, 0, 1, 0, 0]
     * [3, 0, 1, 0, 0]
     * [4, 0, 1, 0, 0]
     * [5, 0, 1, 0, 0]
     * [0, 1, 1, 0, 0]
     * [1, 1, 1, 0, 0]
     * [2, 1, 1, 0, 0]
     * [3, 1, 1, 0, 0]
     * [4, 1, 1, 0, 0]
     * [5, 1, 1, 0, 0]
     * [0, 2, 1, 0, 0]
     * [1, 2, 1, 0, 0]
     * [2, 2, 1, 0, 0]
     * [3, 2, 1, 0, 0]
     * [4, 2, 1, 0, 0]
     * [5, 2, 1, 0, 0]
     * [0, 3, 1, 0, 0]
     * [1, 3, 1, 0, 0]
     * [2, 3, 1, 0, 0]
     * [3, 3, 1, 0, 0]
     * [4, 3, 1, 0, 0]
     * [5, 3, 1, 0, 0]
     * [0, 0, 2, 0, 0]
     * [1, 0, 2, 0, 0]
     * [2, 0, 2, 0, 0]
     * [3, 0, 2, 0, 0]
     * [4, 0, 2, 0, 0]
     * [5, 0, 2, 0, 0]
     * [0, 1, 2, 0, 0]
     * [1, 1, 2, 0, 0]
     * [2, 1, 2, 0, 0]
     * [3, 1, 2, 0, 0]
     * [4, 1, 2, 0, 0]
     * [5, 1, 2, 0, 0]
     * [0, 2, 2, 0, 0]
     * [1, 2, 2, 0, 0]
     * [2, 2, 2, 0, 0]
     * [3, 2, 2, 0, 0]
     * [4, 2, 2, 0, 0]
     * [5, 2, 2, 0, 0]
     * [0, 3, 2, 0, 0]
     * [1, 3, 2, 0, 0]
     * [2, 3, 2, 0, 0]
     * [3, 3, 2, 0, 0]
     * [4, 3, 2, 0, 0]
     * [5, 3, 2, 0, 0]
     * [0, 0, 3, 0, 0]
     * [1, 0, 3, 0, 0]
     * [2, 0, 3, 0, 0]
     * [3, 0, 3, 0, 0]
     * [4, 0, 3, 0, 0]
     * [5, 0, 3, 0, 0]
     * [0, 1, 3, 0, 0]
     * [1, 1, 3, 0, 0]
     * [2, 1, 3, 0, 0]
     * [3, 1, 3, 0, 0]
     * [4, 1, 3, 0, 0]
     * [5, 1, 3, 0, 0]
     * [0, 2, 3, 0, 0]
     * [1, 2, 3, 0, 0]
     * [2, 2, 3, 0, 0]
     * [3, 2, 3, 0, 0]
     * [4, 2, 3, 0, 0]
     * [5, 2, 3, 0, 0]
     * [0, 3, 3, 0, 0]
     * [1, 3, 3, 0, 0]
     * [2, 3, 3, 0, 0]
     * [3, 3, 3, 0, 0]
     * [4, 3, 3, 0, 0]
     * [5, 3, 3, 0, 0]
     * [0, 0, 0, 1, 0]
     * [1, 0, 0, 1, 0]
     * [2, 0, 0, 1, 0]
     * [3, 0, 0, 1, 0]
     * [4, 0, 0, 1, 0]
     *
     * @param add
     * @param ccindex
     * @param maxLen
     * @return
     */
    public static boolean add(int[] add, int ccindex, Integer[] maxLen) {
        boolean isOk = false;
        if (add.length == ccindex + 1) {
            return true;
        }
        if (add[ccindex + 1] <= maxLen[ccindex + 1]) {
            if (add[ccindex + 1] < maxLen[ccindex + 1] - 1) {
                add[ccindex + 1]++;
                for (int m = 0; m < ccindex + 1; m++) {
                    add[m] = 0;
                }
                ccindex = 0;
                isOk = true;
            } else {
                add(add, ++ccindex, maxLen);
                isOk = true;
            }
        }
        return isOk;
    }
}
